package relations;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import nlp.Patterns;
import nlp.PortuguesePOSTagger;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import utils.Pair;
import utils.XMLUtils;
import datasets.Publico.Article;

public class Extract {
	
	static Patterns patterns;
	
	//TODO: check for hipernomia
	//"<ORGANIZACAO>, na <LOCAL>"
	//"<LOCAL>, em <LOCAL>"
	
	
	public static void extractNounPhrasesReverbPatterns(String xml, PortuguesePOSTagger tagger) {
		
	}
			
	/*
	* Processa cada artigo		
	* 
	* 1) Para cada frase com pelo menos duas entidades reconhecidas atribui pos-tags 	
	* 2) Procura padrão ReVerb (rel arg) na frase e procura ent1, mais próxima à esquerda 
	* 	 e ent2 mais próxima à direita, no máximo a 5 tokens de distância do padrão.		
	*/
	
	public static void generatePublico(String xmlFile, PortuguesePOSTagger tagger) throws Exception {		
		System.out.println("Extracting sentences from publico");
		LinkedList<Article> articles = datasets.Publico.ReadXML.returnWithTags(xmlFile);		
		BufferedWriter output_relations = new BufferedWriter(new FileWriter(new File("relations.txt")));
		BufferedWriter output_sentences = new BufferedWriter(new FileWriter(new File("sentences.txt")));
		int processed = 0;
		int id = 0;
		for (Article article : articles) {
			processed += 1;
			if (processed % 1000 == 0) System.out.println(processed+"/"+articles.size());			
			String text = cleanArticle(article.text);
			for (String s : tagger.sentence.sentDetect(text)) {
				extractPairsRelation(tagger, output_relations, output_sentences, id, s, article.text);
				output_sentences.write(String.valueOf(id) + '\t' + s.trim().replaceAll("\n", " ") + '\n');
				id++;				
			}
		}
		output_relations.close();
		output_sentences.close();
	}


	/*
	 * Cleans the article so that it is valid XML and doesn't contain unseen characters/words by the POS-tagger   
	 */
	static String cleanArticle(String text) {
		//apply regular expressions to make valid XML
		text = text.replaceAll("&","&amp;");
		
		//remove unknown characters by CINTIL
		text = text.replaceAll("–","-"); //TODO: confirmar que é feitar a substituição
		text = text.replaceAll("“\\s","\\\" ").replaceAll("\\s”\\."," \\\"\\.").replaceAll("\\s”,"," \\\",").replaceAll("\\s”\\."," \\\"\\.").replaceAll(" ” "," \\\" ");
		
		//fix some REMBRANDT stupid bugs
		Pattern regex = Pattern.compile("<LOCAL><ORGANIZACAO>([^<]+)</ORGANIZACAO>");
		Matcher matcher = regex.matcher(text);
		while (matcher.find()) text = matcher.replaceAll("<ORGANIZACAO>"+matcher.group(1)+"</ORGANIZACAO>");
		
		regex = Pattern.compile("<LOCAL><PESSOA>([^<]+)</PESSOA>");
		matcher = regex.matcher(text);
		while (matcher.find()) text = matcher.replaceAll("<PESSOA>"+matcher.group(1)+"</PESSOA>");

		regex = Pattern.compile("<ORGANIZACAO><PESSOA>([^<]+)</PESSOA>");
		matcher = regex.matcher(text);
		while (matcher.find()) text = matcher.replaceAll("<PESSOA>"+matcher.group(1)+"</PESSOA>");
		
		//replaces occurences of  "... qq coisa .É ..." replace to "... qq coisa. É ..." this occurred due to scraping errors			
		regex = Pattern.compile(" \\.([A-Za-z]+)");
		matcher = regex.matcher(text);
		StringBuffer sb = new StringBuffer();
		boolean found = false;
		while (matcher.find()) {
			found = true;
			matcher.appendReplacement(sb, ". "+matcher.group(1));
		}
		if (found) {
			matcher.appendTail(sb);
			text = sb.toString();
		}
		
		 /* O sentence dectector separar nomes como os abaixo, em duas frases:
		 * <PESSOA>Presidente George W. Bush</PESSOA>
		 * <PESSOA>H. David Politzer</PESSOA>
		 * <PESSOA>D. Quixote</PESSOA>
		 * <PESSOA>J. Craig Venter Institute</PESSOA>
		 * <PESSOA>Prof. Doutor Aníbal Cavaco Silva</PESSOA>.
		 * <ORGANIZACAO>Escola Secundária Dr. Manuel Candeias Gonçalves</ORGANIZACAO>
		 * <PESSOA>C.G. Jung</PESSOA>
		 * mais exemplos: grep -oP '<[^/a-z>]*>[^>]+\s[A-Za-z]+\.[^>]+</[^>]+>' publico-10-anos.xml
		 * 
		 *  retirar o "." da letra capitalizada no meio
		 */
		/*
		MATCHER:<PESSOA>Valter D. Longo</PESSOA>
		REPLACE:<PESSOA>Valter D Longo</PESSOA>
		MATCHER:<PESSOA>António M. Hespanha</PESSOA>
		MATCHER:<PESSOA>Richard R. Berhringer</PESSOA>
		REPLACE:<PESSOA>Richard R Berhringer</PESSOA>
		MATCHER:<PESSOA>Mr. Clinton</PESSOA>
		REPLACE:<PESSOA>Mr Clinton</PESSOA>
		MATCHER:<PESSOA>George W. Bush</PESSOA>
		MATCHER:<PESSOA>George W Bush</PESSOA>
		*/
		regex = Pattern.compile("(<[^/a-z>]*>[^>]+\\s?[A-Za-z]+)\\.([^>]+</[^>]+>)");
		matcher = regex.matcher(text);
		while (matcher.find()) text = matcher.replaceAll(matcher.group(1) + matcher.group(2));
		
		/*
		MATCHER:<PESSOA>M. Night Shyamalan</PESSOA>
		REPLACE:<PESSOA>M Night Shyamalan</PESSOA>
		MATCHER:<PESSOA>D. Maria de Noronha</PESSOA>
		REPLACE:<PESSOA>D Maria de Noronha</PESSOA>
		MATCHER:<LOCAL>Av. da República</LOCAL>
		REPLACE:<LOCAL>Av da República</LOCAL>
		*/
		regex = Pattern.compile("(<[^/a-z>]*>[A-Za-z]+)\\.([^>]+</[^>]+>)");
		matcher = regex.matcher(text);
		while (matcher.find()) text = matcher.replaceAll(matcher.group(1) + matcher.group(2));
		
		/*
		MATCHER: <PESSOA>AD. Miller</PESSOA>
		REPLACE: <PESSOA>AD Miller</PESSOA>
		MATCHER: <PESSOA>CG. Jung</PESSOA>
		REPLACE: <PESSOA>CG Jung</PESSOA>
		MATCHER: <PESSOA>JK. Rowling</PESSOA>
		REPLACE: <PESSOA>JK Rowling</PESSOA>
		MATCHER: <PESSOA>BB. King</PESSOA>
		REPLACE: <PESSOA>BB King</PESSOA>
		*/
		regex = Pattern.compile("(<[^/a-z>]*>[A-Z]+)\\.([^>]+</[^>]+>)");
		matcher = regex.matcher(text);
		while (matcher.find()) text = matcher.replaceAll(matcher.group(1) + matcher.group(2));			
		
		/*
		<PESSOA>Paul W.S Anderson</PESSOA>		
		<PESSOA>arquitectos C.F. Møller</PESSOA>
		<PESSOA>E T. A Hoffmann</PESSOA>
		<ORGANIZACAO>IAT.H,SA</ORGANIZACAO>
		<LOCAL>Convento de N. S da Estrela</LOCAL>
		<PESSOA>Ronald Reagan Presidente e George H. W Bush</PESSOA>
		<ORGANIZACAO>Fundação T.J. Martell</ORGANIZACAO>>		
		<PESSOA> Dr. João Brito Camacho</PESSOA>
		<PESSOA> C.J. Jordan</PESSOA>
		<PESSOA>J.R.R. Tolkien</PESSOA>
		<PESSOA>R.I.P. Batman</PESSOA>
		<PESSOA>Carlos H. C. Silva</PESSOA>
		<LOCAL>Convento de N. S. da Estrela</LOCAL>
		*/
		
		/*
		<PESSOA>Fernando JB. Martinho</PESSOA>
		<PESSOA>ministro GK. Pillai</PESSOA>
		<PESSOA>vice-presidente da AT. Kerney</PESSOA>
		<ORGANIZACAO>Fundação TJ. Martell</ORGANIZACAO
		*/

		//42.500 euros
		regex = Pattern.compile("(<[^/a-z>]*>[^<]+)([0-9]+)\\.([0-9]+)(\\s[^<]+</[^>]+>)");
		matcher = regex.matcher(text);
		while (matcher.find()) text = matcher.replaceAll(matcher.group(1) + matcher.group(2) + ' ' + matcher.group(3) + matcher.group(4));		
		text = text.replaceAll("Prç.", "Prç").replaceAll("Dr.", "Dr");
		
		return text;
	}
	
	static void extractPairsRelation(PortuguesePOSTagger tagger,BufferedWriter output_relations, BufferedWriter output_sentences, int id, String s, String article) {	
		Document xml = null;		
		try {
			xml = XMLUtils.loadXMLFromString("<root>"+s+"</root>");
			NodeList local = xml.getElementsByTagName("LOCAL");
			NodeList pessoa = xml.getElementsByTagName("PESSOA");
			NodeList organizacao = xml.getElementsByTagName("ORGANIZACAO");

			//check if sentence contains at least 2 entities
			if (local.getLength() + pessoa.getLength() + organizacao.getLength() > 2 ) {				
				Pair<String[],String[]> tagged = tagger.tagSentence(s.replaceAll("<[^>]*>", ""));					
				String[] tokens = tagged.getFirst();
				String[] tags	= tagged.getSecond();
				
				//extract all ReVerb patterns
				List<ArrayList<Integer>> tokensRelArg = Patterns.extractReVerbPatterns(tokens,tags);				
				
				if (tokens.length==tags.length) {
					///ir buscar todos os pares de entidades
					Pattern pattern = Pattern.compile("<[^>]*>[^<]+</[^>]+>");
                    Matcher matcher = pattern.matcher(s);
                    while (matcher.find()) {
                    	String type1 = matcher.group();
                    	String after1 = s.substring(matcher.end());
                    	Matcher matcher2 = pattern.matcher(after1);
                        while (matcher2.find()) {
                        	String type2 = matcher2.group();
                            //get position of ent1 and ent2 in the tokens array
							String[] ent1_tokens = type1.replaceAll("<[^>]*>", "").split(" ");
							String[] ent2_tokens = type2.replaceAll("<[^>]*>", "").split(" ");							
							ArrayList<String> tokensTokens = new ArrayList<String>(tokens.length);
							ArrayList<String> ent1Tokens = new ArrayList<String>(ent1_tokens.length);
							ArrayList<String> ent2Tokens = new ArrayList<String>(ent2_tokens.length);										
							for (String n : ent1_tokens) ent1Tokens.add(n);
							for (String n : ent2_tokens) ent2Tokens.add(n);
							for (String n : tokens) tokensTokens.add(n);							
							//get the extremes of the entities in the tokens array
							int ent1_last = tokensTokens.indexOf(ent1Tokens.get((ent1Tokens.size()-1)));
							int ent2_first = tokensTokens.indexOf(ent2Tokens.get(0));							
                            //check if pattern is between the two named-entities
                            for (ArrayList<Integer> arrayList : tokensRelArg) {                            	
                            	//get the extremes of the pattern in the tokens array    							
                            	int first = arrayList.get(0);
    							int last  = arrayList.get(arrayList.size()-1);    							    						
    							//TODO: por mais uma restrição no tamanho do pattern
    							if ((first>ent1_last) && (ent2_first>last) && ent2_first-ent1_last<=10) {    								
    								String pattern_tokens_pos = new String();    								
    								String pattern_tokens = new String();
    								for (Integer i : arrayList) {
    									pattern_tokens += tokens[i] + ' ';
    									pattern_tokens_pos	+= tokens[i] + '/' + tags[i] + ' '; 
									}
    								output_relations.write(String.valueOf(id) + '\t' + type1 +'\t' + pattern_tokens + '\t' + type2 + '\t' + pattern_tokens_pos + '\n');
    							}
							}
                        }
                    }
				}
				else {
					System.out.println("Error!");
					System.exit(0);
				}
			}
		}
		catch (Exception e) {
			e.printStackTrace();
			System.out.println(s+'\n');
			}
	}	
}
